package com.xpresso.utils.system;

import java.io.*;

import org.apache.log4j.Logger;

import com.xpresso.utils.exceptions.XpressoException;

class StreamGobbler extends Thread {
    
	InputStream is;
    String type;
    StringBuffer cOutput;
    CommandLineListener listener;
    
    private static final Logger log = Logger.getLogger(StreamGobbler.class);
    
    StreamGobbler(InputStream is, String type, StringBuffer sb){
        this.is = is;
        this.type = type;
        this.cOutput = sb;
    }
    
    StreamGobbler(InputStream is, String type, StringBuffer sb, CommandLineListener listener){
        this.is = is;
        this.type = type;
        this.cOutput = sb;
        this.listener = listener;
    }    
    
    public void run(){
        try{
	        InputStreamReader isr = new InputStreamReader(is);
	        BufferedReader br = new BufferedReader(isr);
	        String line=null;
	        while ((line = br.readLine()) != null){
	        	this.cOutput.append(line + "\n");
	        	if (this.listener != null){
		        	if (type.equals("OUTPUT")){
		        		this.listener.handleOutputMessage(line);
		        	} else {
		        		this.listener.handleErrorMessage(line);
		        	}
	        	}
	        }
        } catch (IOException ioe){
            ioe.printStackTrace();  
        }
    }
    
    public String getOutput(){
    	if (this.cOutput != null){
    		return this.cOutput.toString();
    	}
    	return null;
    }
    
}

public class CommandLine {

	private static final Logger log = Logger.getLogger(CommandLine.class);
	
	public CommandLine(){
		
	}
	
	public CommandResult exec(String command, CommandLineListener listener) throws XpressoException{
        CommandResult result = new CommandResult();
        result.setExitValue(-1);
		try{            
            String osName = System.getProperty("os.name" );
            System.out.println(osName);
            log.info("Operating system: " + osName);
            
            String[] cmd = new String[3];
            if(osName.equals("Windows NT") || osName.equals("Windows XP")){
                cmd[0] = "cmd.exe" ;
                cmd[1] = "/C" ;
                cmd[2] = command;
            } else if( osName.equals("Windows 95")){
                cmd[0] = "command.com" ;
                cmd[1] = "/C" ;
                cmd[2] = command;
            } else if (osName.equals("Linux") || osName.equals("Mac OS X")){
            	cmd[0]= "bash";
            	cmd[1] = "-c";
            	cmd[2] = command;
            }
            
            Runtime rt = Runtime.getRuntime();
            log.info("Executing " + cmd[0] + " " + cmd[1] + " " + cmd[2]);
            
            Process proc = rt.exec(cmd);
            log.info("After the command was executed");
            
            StringBuffer eOutput = new StringBuffer();
            StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR", eOutput, listener);            
            
            StringBuffer cOutput = new StringBuffer();
            StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", cOutput, listener);
                
            // kick them off
            errorGobbler.start();
            outputGobbler.start();
            
            // any error???
            int exitVal = proc.waitFor();
            log.info("Exit value: " + exitVal);
            
            result.setExitValue(exitVal);
            result.setFinalError(eOutput.toString());
            result.setFinalOutput(cOutput.toString());
            
        } catch (Throwable t){
            log.error("An error ocurred executing command: " + command);
            throw new XpressoException("An error ocurred executing command: " + command, new Exception(t));
        }
		
		return result;
	}
	
	
	
	public static void execute(String command) throws XpressoException{
        try{            
            String osName = System.getProperty("os.name" );
            System.out.println(osName);
            log.info("Operating system: " + osName);
            
            String[] cmd = new String[3];
            if(osName.equals("Windows NT") || osName.equals("Windows XP")){
                cmd[0] = "cmd.exe" ;
                cmd[1] = "/C" ;
                cmd[2] = command;
            } else if( osName.equals("Windows 95")){
                cmd[0] = "command.com" ;
                cmd[1] = "/C" ;
                cmd[2] = command;
            } else if (osName.equals("Linux") || osName.equals("Mac OS X")){
            	cmd[0]= "bash";
            	cmd[1] = "-c";
            	cmd[2] = command;
            }
            
            Runtime rt = Runtime.getRuntime();
            System.out.println("Executing " + cmd[0] + " " + cmd[1] 
                               + " " + cmd[2]);
            
            log.info("Executing " + cmd[0] + " " + cmd[1] 
                                                     + " " + cmd[2]);
            
            Process proc = rt.exec(cmd);
            
            StringBuffer eOutput = new StringBuffer();
            // any error message?
            StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR", eOutput);            
            
            log.info("After the command was executed");
            
            StringBuffer cOutput = new StringBuffer();
            // any output?
            StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT", cOutput);
                
            // kick them off
            errorGobbler.start();
            outputGobbler.start();
            
            // any error???
            int exitVal = proc.waitFor();
            System.out.println("ExitValue: " + exitVal);
            log.info("ExitValue: " + exitVal);
            
            System.out.println("Comand output: " + cOutput.toString());
            System.out.println("Error output: " + eOutput.toString());
            
        } catch (Throwable t){
            t.printStackTrace();
        }
    }
}